/*
 * Título: gestHora. Aplicación web de gestión de horarios para conservatorios.
 * Alumnos:
 * - Javier Pardo Muñoz. I.T. Informática de Gestión
 * - Antonio Prior Cazorla. I.T. Informática de Gestión
 * Director: Dr. José Raúl Romero Salguero.
 *     
 *  Copyright (C) 2013 Javier Pardo Muñoz / Antonio Prior Cazorla
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package es.uco.gesthora.business.algoritmo;

import es.uco.gesthora.business.GenerarHorarios;
import java.util.Vector;

public class Arbol {

    /**
     * Se encarga de rellenar el arbol con cada una de las solicitudes posibles
     *
     * @param solicitudes: Un vector que contiene 1 ò 0 dependiendo de si dicho
     * grupo esta dentro del horario o no
     * @param antModif: Muestra la anterior modificación
     * @param antHemano: Señala el hermano anterior
     * @param numeroAsignaturas: Número de asignaturas en las que el alumnos
     * esta matriculado
     * @param valorMax: Valor del nodo que hay que buscar
     * @param infoSolicitudes: Vector con toda la información necesaria sobre
     * las solicitudes
     * @param padre: Nodo padre del nodo actual
     * @param raiz: Nodo raiz del arbol
     *
     * @return Nodo mejor retorna el mejor valor del arbol
     */
    public Nodo rellenarArbol(Vector solicitudes, int antModif, Nodo antHermano, int numeroAsignaturas, int valorMax, Vector<Solicitud> infoSolicitudes, Nodo padre, Nodo raiz) {
        //Declaración de variables
        GenerarHorarios generarHorarios = GenerarHorarios.getInstance();
        Nodo nodoHijo = new Nodo();
        Nodo nodoHermano = new Nodo();
        //Crear nodo actual.
        Nodo nodo = new Nodo(generarHorarios.valorarSolicitud(solicitudes, numeroAsignaturas, infoSolicitudes), solicitudes);
        //Enlazar el nodo actual con el padre o con el hermano.
        if (antHermano == null) {
            padre.setHijo(nodo);
        } else {
            antHermano.setHermano(nodo);
        }
        //Si el nodoactual tiene un valor mayor al valor maximo del arbol no se sigue rellenando el arbol.
        if (nodo.getValor() >= valorMax) {
            System.out.println("Encontrado nodo y retornado VALOR = " + nodo.getValor());
            return nodo;
        } else {

            Vector solicitudHijo = new Vector();
            Vector solicitudHermano = new Vector();
            //rellenar solicitudesHijo y solicitudesHermano
            for (int i = 0; i < solicitudes.size(); i++) {
                solicitudHijo.addElement(solicitudes.get(i));
                if (i != antModif) {
                    solicitudHermano.addElement(solicitudes.get(i));
                } else {
                    solicitudHermano.addElement(0);
                }
            }
            //Se crean los descendientes del nodo actual.
            int hermano = 0;
            int hijo = 0;
            int e = antModif + 1;
            int a = 0;
            while (a < solicitudes.size() && hijo == 0) {
                //Se valida la solicitudHijo
                if (generarHorarios.validarSolicitud(solicitudHijo, a, infoSolicitudes)) {
                    solicitudHijo.set(a, 1);
                    //Si la solicitudHijo no existe en el arbol entonces se inserta
                    if (!buscarNodoexistente(solicitudHijo, raiz)) {
                        nodoHijo = rellenarArbol(solicitudHijo, a, null, numeroAsignaturas, valorMax, infoSolicitudes, nodo, raiz);
                        hijo = 1;
                    } else {
                        solicitudHijo.set(a, 0);
                    }
                }
                a++;
            }
            //Si los descendientes del nodo actual nos devuelve un nodo con valor mayor al valor maximo entonces retornamos el nodoHijo, sino se crean los Nodohermanos 
            if (nodoHijo.getValor() < valorMax) {
                while (e < solicitudes.size() && hermano == 0) {
                    //Se validad solicitudHermano
                    if (generarHorarios.validarSolicitud(solicitudHermano, e, infoSolicitudes)) {
                        solicitudHermano.set(e, 1);
                        //Si la solicitudHermano no existe en el arbol entonces se inserta
                        if (!buscarNodoexistente(solicitudHermano, raiz)) {
                            nodoHermano = rellenarArbol(solicitudHermano, e, nodo, numeroAsignaturas, valorMax, infoSolicitudes, padre, raiz);
                            hermano = 1;
                        } else {
                            solicitudHermano.set(e, 0);
                        }
                    }
                    e++;
                }
            } else {
                return nodoHijo;
            }
        }
        //Se retorna el nodo con mejor valor
        if (nodoHijo.getValor() > nodoHermano.getValor()) {
            if (nodoHijo.getValor() > nodo.getValor()) {
                return nodoHijo;
            }
        } else {
            if (nodoHermano.getValor() > nodo.getValor()) {
                return nodoHermano;
            }
        }
        return nodo;
    }

    /**
     * Se encarga de buscar si un nodo existe o no en el arbol
     *
     * @param solicitud: Un vector que contiene 1 ò 0 dependiendo de si dicho
     * grupo esta dentro del horario o no
     * @param actual: Indica el nodo en donde se encuentra actualmente
     *
     * @return True si existe dicha solicitud en el arbol/ False si no existe
     */
    public boolean buscarNodoexistente(Vector solicitud, Nodo actual) {
        //Declaración de variables
        boolean bHijo = false;
        boolean bHermano = false;
        int cont = 0;
        //Mira si el nodo actual es igual a la solicitud
        for (int i = 0; i < solicitud.size(); i++) {
            if (actual.getSolicitud().get(i) == solicitud.get(i)) {
                cont++;
            }
        }
        //Si el numero de elementos es igual a la longitud del vector solicitud, entonces devuelve true
        if (cont == solicitud.size()) {
            return true;
        } else {
            //Si nodo actual tiene hijos busca la solicitud en ellos
            if (actual.getHijo() != null) {
                bHijo = buscarNodoexistente(solicitud, actual.getHijo());
            }
            //Si nodo actual tiene hermanos busca la solicitud en ellos
            if (actual.getHermano() != null) {
                bHermano = buscarNodoexistente(solicitud, actual.getHermano());
            }
            //Si la busqueda en los hijos o en los hermanos ha devuelto un true, entonces devuelve true
            if (bHijo || bHermano) {
                return true;
            }
        }
        return false;

    }

    /**
     * Se encarga encarga de contar todos los nodos de un arbol
     *
     * @param actual: Indica el nodo en donde se encuentra actualmente
     *
     * @return Devuelve el numero de nodos del arbol
     */
    public int contarNodos(Nodo actual) {
        int resultado = 1;
        if (actual != null) {
            //Si actual tiene hijos, entonces cuenta el numero de hijos
            if (actual.getHijo() != null) {
                resultado = resultado + contarNodos(actual.getHijo());
            }
            //Si actual tiene hermanos, entonces cuenta el numero de hermanos y sus descendientes
            if (actual.getHermano() != null) {
                resultado = resultado + contarNodos(actual.getHermano());
            }
        }
        return resultado;
    }

    /**
     * Se encarga de recorrer todo el arbol
     *
     * @param actual: Indica el nodo en donde se encuentra actualmente
     *
     * @return No devuelve nada
     */
    public void recorrerArbol(Nodo actual) {
        System.out.println("Valor: " + actual.getValor() + "- Solicitud: " + actual.getStringSolicitud());
        if (actual != null) {
            //Si actual tiene hijos, entonces los recorre
            if (actual.getHijo() != null) {
                recorrerArbol(actual.getHijo());
            }
            //Si actual tiene hijos, entonces los recorre
            if (actual.getHermano() != null) {
                recorrerArbol(actual.getHermano());
            }
        }
    }
    /**
     * recorre todo el arbol y devuelve el mejor nodo.
     *
     * @param actual: Nodo actual
     * @param mejor: Nodo mejor
     * @return devuelve el mejor nodo
     */
    /* public Nodo mejorNodo(Nodo actual, Nodo mejor) {
     //System.out.println("-" + actual.getValor());
     Nodo mejorHijo = mejor;
     Nodo mejorHermano = mejor;
     if (actual != null) {
     mejorHijo = actual;
     mejorHermano = actual;
     if (actual.getValor() > mejor.getValor()) {
     if (actual.getHijo() != null) {
     mejorHijo = mejorNodo(actual.getHijo(), actual);
     }
     if (actual.getHermano() != null) {
     mejorHermano = mejorNodo(actual.getHermano(), actual);
     }
     } else {
     if (actual.getHijo() != null) {
     mejorHijo = mejorNodo(actual.getHijo(), mejor);
     }
     if (actual.getHermano() != null) {
     mejorHermano = mejorNodo(actual.getHermano(), mejor);
     }
     }
     if (mejorHijo.getValor() > mejorHermano.getValor()) {
     mejor = mejorHijo;
     } else {
     mejor = mejorHermano;
     }
     }
     return mejor;
     }*/
}
